OPC Studio User's Guide and Reference
ValueType<TValue>(UADataVariable) Method
Example 



OpcLabs.ServerOpcUA Assembly > OpcLabs.EasyOpc.UA.NodeSpace Namespace > UADataVariableExtension Class > ValueType Method : ValueType<TValue>(UADataVariable) Method
The type of the value of the data variable.
The data variable that will be modified and returned.

The value of this parameter cannot be null (Nothing in Visual Basic).

Makes the data variable to use the value type specified by a generic parameter.
Syntax
'Declaration
 
<ExtensionAttribute()>
<NotNullAttribute()>
Public Overloads Shared Function ValueType(Of TValue)( _
   ByVal dataVariable As UADataVariable _
) As UADataVariable
'Usage
 
Dim dataVariable As UADataVariable
Dim value As UADataVariable
 
value = UADataVariableExtension.ValueType(Of TValue)(dataVariable)
[Extension()]
[NotNull()]
public static UADataVariable ValueType<TValue>( 
   UADataVariable dataVariable
)
[Extension()]
[NotNull()]
public:
static UADataVariable^ ValueTypegeneric<typename TValue>
( 
   UADataVariable^ dataVariable
) 

Parameters

dataVariable
The data variable that will be modified and returned.

The value of this parameter cannot be null (Nothing in Visual Basic).

Type Parameters

TValue
The type of the value of the data variable.

Return Value

Returns the dataVariable, internally modified as defined by the method.

This method never returns null (Nothing in Visual Basic).

Exceptions
ExceptionDescription

A null reference (Nothing in Visual Basic) is passed to a method that does not accept it as a valid argument.

This is a usage error, i.e. it will never occur (the exception will not be thrown) in a correctly written program. Your code should not catch this exception.

Remarks

This method overload infers the OPC data type and value rank of the data variable from the TValue type.

This is an extension method (info: C#, VB.NET). In languages that have support for extensions methods (such as C# and VB.NET), you can use the extension method as if it were a regular method on the object that is its first parameter. In other languages (such as with Python.NET), you will call the extension as a static method, and pass it the object on which it acts as its first parameter.

Example
// This example shows how to set the attribute data in the push data provision model. In this model, your code pushes the
// data into the server, and the server then makes the data available to OPC clients.
// You can use any OPC UA client, including our Connectivity Explorer and OpcCmd utility, to connect to the server. 
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
// OPC client, server and subscriber examples in C# on GitHub: https://github.com/OPCLabs/Examples-OPCStudio-CSharp .
// Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
// a commercial license in order to use Online Forums, and we reply to every post.

using System;
using System.Timers;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.NodeSpace;

namespace UAServerDocExamples._UADataVariable
{
    class ReadAttributeData
    {
        public static void Main1()
        {
            // Instantiate the server object.
            // By default, the server will run on endpoint URL "opc.tcp://localhost:48040/".
            var server = new EasyUAServer();

            // Create a read-only data variable.
            var dataVariable = UADataVariable.CreateIn(server.Objects, "ReadThisVariable")
                .ValueType<int>()
                .Writable(false);

            // Create a timer for pushing the data for OPC reads. In a real server the activity may also come from other
            // sources.
            var timer = new Timer
            {
                Interval = 1000,
                AutoReset = true,
            };

            // Set the read attribute data of the data variable to a random value whenever the timer interval elapses.
            // Note that this example shows the basic concept, however there is also an UpdateReadAttributeData method that
            // can be used in most cases to achieve slightly more concise code.
            var random = new Random();
            timer.Elapsed += (sender, args) => 
                dataVariable.ReadAttributeData = new UAAttributeData(random.Next(), DateTime.UtcNow);
            timer.Start();

            // Start the server.
            Console.WriteLine("The server is starting...");
            server.Start();

            Console.WriteLine("The server is started.");
            Console.WriteLine();

            // Let the user decide when to stop.
            Console.WriteLine("Press Enter to stop the server...");
            Console.ReadLine();

            // Stop the server.
            Console.WriteLine("The server is stopping...");
            server.Stop();

            // Stop the timer.
            timer.Stop();

            Console.WriteLine("The server is stopped.");
        }
    }
}
' This example shows how to set the attribute data in the push data provision model. In this model, your code pushes the
' data into the server, and the server then makes the data available to OPC clients.
' You can use any OPC UA client, including our Connectivity Explorer and OpcCmd utility, to connect to the server. 
'
' Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
' OPC client and subscriber examples in VB.NET on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-VBNET .
' Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
' a commercial license in order to use Online Forums, and we reply to every post.

Imports System
Imports System.Timers
Imports OpcLabs.EasyOpc.UA
Imports OpcLabs.EasyOpc.UA.NodeSpace

Namespace _UADataVariable
    Partial Friend Class ReadAttributeData
        Shared Sub Main1()
            ' Instantiate the server object.
            ' By default, the server will run on endpoint URL "opc.tcp://localhost:48040/".
            Dim server = New EasyUAServer()

            ' Create a read-only data variable.
            Dim dataVariable = UADataVariable.CreateIn(server.Objects, "ReadThisVariable") _
                .ValueType(Of Integer)() _
                .Writable(False)

            ' Create a timer for pushing the data for OPC reads. In a real server the activity may also come from other
            ' sources.
            Dim timer = New Timer With
            {
                .Interval = 1000,
                .AutoReset = True
            }

            ' Set the read attribute data of the data variable to a random value whenever the timer interval elapses.
            ' Note that this example shows the basic concept, however there is also an UpdateReadAttributeData method that
            ' can be used in most cases to achieve slightly more concise code.
            Dim random = New Random()
            AddHandler timer.Elapsed, Sub(sender, args) dataVariable.ReadAttributeData = New UAAttributeData(random.Next(), DateTime.UtcNow)
            timer.Start()

            ' Start the server.
            Console.WriteLine("The server is starting...")
            server.Start()

            Console.WriteLine("The server is started.")
            Console.WriteLine()

            ' Let the user decide when to stop.
            Console.WriteLine("Press Enter to stop the server...")
            Console.ReadLine()

            ' Stop the server.
            Console.WriteLine("The server is stopping...")
            server.Stop()

            Console.WriteLine("The server is stopped.")
        End Sub
    End Class
End Namespace
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
// OPC client, server and subscriber examples in C# on GitHub: https://github.com/OPCLabs/Examples-OPCStudio-CSharp .
// Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
// a commercial license in order to use Online Forums, and we reply to every post.

using System;
using OpcLabs.EasyOpc.UA.AddressSpace.Standard;
using OpcLabs.EasyOpc.UA.NodeSpace;

namespace UAServerDemoLibrary
{
    static public class DataNodes
    {
        /// <summary>
        /// Adds static and dynamic nodes that demonstrate various data types and access levels.
        /// </summary>
        /// <param name="parentFolder">The folder to which to add the nodes.</param>
        static public void AddToParent(UAFolder parentFolder)
        {
            // Create Data folder.
            UAFolder dataFolder = UAFolder.CreateIn(parentFolder, "Data");

            // Create read-only data variables of various data types, without adding them to the server first. We store
            // references to them individually, because we later implement write-only variables that write to these
            // read-only variables.
            UADataVariable booleanReadOnlyDataVariable =
                new UADataVariable("BooleanValue").Writable(false).ValueType<bool>();
            UADataVariable byteStringReadOnlyDataVariable =
                new UADataVariable("ByteStringValue").Writable(false).ValueType<byte[]>();
            UADataVariable byteReadOnlyDataVariable = new UADataVariable("ByteValue").Writable(false).ValueType<byte>();
            UADataVariable dateTimeReadOnlyDataVariable =
                new UADataVariable("DateTimeValue").Writable(false).ValueType<DateTime>();
            UADataVariable doubleReadOnlyDataVariable =
                new UADataVariable("DoubleValue").Writable(false).ValueType<double>();
            UADataVariable floatReadOnlyDataVariable =
                new UADataVariable("FloatValue").Writable(false).ValueType<float>();
            UADataVariable guidReadOnlyDataVariable = new UADataVariable("GuidValue").Writable(false).ValueType<Guid>();
            UADataVariable int16ReadOnlyDataVariable =
                new UADataVariable("Int16Value").Writable(false).ValueType<short>();
            UADataVariable int32ReadOnlyDataVariable =
                new UADataVariable("Int32Value").Writable(false).ValueType<int>();
            UADataVariable int64ReadOnlyDataVariable =
                new UADataVariable("Int64Value").Writable(false).ValueType<long>();
            UADataVariable sByteReadOnlyDataVariable =
                new UADataVariable("SByteValue").Writable(false).ValueType<sbyte>();
            UADataVariable stringReadOnlyDataVariable =
                new UADataVariable("StringValue").Writable(false).ValueType<string>();
            UADataVariable uInt16ReadOnlyDataVariable =
                new UADataVariable("UInt16Value").Writable(false).ValueType<ushort>();
            UADataVariable uInt32ReadOnlyDataVariable =
                new UADataVariable("UInt32Value").Writable(false).ValueType<uint>();
            UADataVariable uInt64ReadOnlyDataVariable =
                new UADataVariable("UInt64Value").Writable(false).ValueType<ulong>();
            UADataVariable variantReadOnlyDataVariable =
                new UADataVariable("VariantValue").Writable(false);

            // Create Constant sub-folder under the Data folder. It contains read-only data variables with constant values.
            dataFolder.Add(
                new UAFolder("Constant")
                {
                    new UAFolder("Scalar")
                    {
                        new UADataVariable("BooleanValue").ConstantValue(true),
                        new UADataVariable("ByteStringValue").ConstantValue(new byte[] { 0x57, 0x21, 0x40, 0xfc }),
                        new UADataVariable("ByteValue").ConstantValue((byte)144),
                        new UADataVariable("DateTimeValue").ConstantValue(
                            // We are passing in UTC times, because we want always the same result, and so we must specify
                            // the DateTimeKind. You can pass in local times, but then they will be converted to UTC by the
                            // server, and the result will depend on the time zone.
                            DateTime.SpecifyKind(new DateTime(2024, 7, 12, 14, 4, 55).AddSeconds(0.444),
                                DateTimeKind.Utc)),
                        new UADataVariable("DoubleValue").ConstantValue(7.75630105797e-011),
                        new UADataVariable("FloatValue").ConstantValue(2.77002e+29f),
                        new UADataVariable("GuidValue").ConstantValue(
                            new Guid("{1AEF59AE-5029-42A7-9AE2-B2DC00072999}")),
                        new UADataVariable("Int16Value").ConstantValue((short)-30956),
                        new UADataVariable("Int32Value").ConstantValue(276673160),
                        new UADataVariable("Int64Value").ConstantValue(1412096336825367659),
                        new UADataVariable("SByteValue").ConstantValue((sbyte)-113),
                        new UADataVariable("StringValue").ConstantValue("lorem ipsum"),
                        new UADataVariable("UInt16Value").ConstantValue((ushort)64421),
                        new UADataVariable("UInt32Value").ConstantValue(3853116537U),
                        new UADataVariable("UInt64Value").ConstantValue(9431348106520835314UL),
                        new UADataVariable("VariantValue").ConstantValue(529739609)
                    }
                });

            // Create Dynamic sub-folder under the Data folder. It contains data variables with dynamically changing values.
            dataFolder.Add(
                new UAFolder("Dynamic")
                {
                    new UAFolder("Array")
                    {
                        new UADataVariable("BooleanValue").ReadValueFunction(() => NextRandomArray(NextRandomBoolean)),
                        new UADataVariable("ByteStringValue").ReadValueFunction(() =>
                            NextRandomArray(NextRandomByteString)),
                        // This is a tricky case. We want array of Byte-s, but that is automatically recognized as scalar
                        // OPC UA ByteString. For a true array of Byte-s, the data type Id and array dimension list must be
                        // specified explicitly.
                        new UADataVariable("ByteValue").ReadValueFunction(
                            dataTypeId: UADataTypeIds.Byte,
                            arrayRank: 1,
                            () => NextRandomArray(NextRandomByte)),
                        new UADataVariable("DateTimeValue").ReadValueFunction(() =>
                            NextRandomArray(NextRandomDateTime)),
                        new UADataVariable("DoubleValue").ReadValueFunction(() => NextRandomArray(NextRandomDouble)),
                        new UADataVariable("FloatValue").ReadValueFunction(() => NextRandomArray(NextRandomFloat)),
                        new UADataVariable("GuidValue").ReadValueFunction(() => NextRandomArray(NextRandomGuid)),
                        new UADataVariable("Int16Value").ReadValueFunction(() => NextRandomArray(NextRandomInt16)),
                        new UADataVariable("Int32Value").ReadValueFunction(() => NextRandomArray(NextRandomInt32)),
                        new UADataVariable("Int64Value").ReadValueFunction(() => NextRandomArray(NextRandomInt64)),
                        new UADataVariable("SByteValue").ReadValueFunction(() => NextRandomArray(NextRandomSByte)),
                        new UADataVariable("StringValue").ReadValueFunction(() => NextRandomArray(NextRandomString)),
                        new UADataVariable("UInt16Value").ReadValueFunction(() => NextRandomArray(NextRandomUInt16)),
                        new UADataVariable("UInt32Value").ReadValueFunction(() => NextRandomArray(NextRandomUInt32)),
                        new UADataVariable("UInt64Value").ReadValueFunction(() => NextRandomArray(NextRandomUInt64)),
                        new UADataVariable("VariantValue").ReadValueFunction(() => NextRandomArray(NextRandomVariant))
                    },

                    new UAFolder("Scalar")
                    {
                        new UADataVariable("BooleanValue").ReadValueFunction(NextRandomBoolean),
                        new UADataVariable("ByteStringValue").ReadValueFunction(NextRandomByteString),
                        new UADataVariable("ByteValue").ReadValueFunction(NextRandomByte),
                        new UADataVariable("DateTimeValue").ReadValueFunction(NextRandomDateTime),
                        new UADataVariable("DoubleValue").ReadValueFunction(NextRandomDouble),
                        new UADataVariable("FloatValue").ReadValueFunction(NextRandomFloat),
                        new UADataVariable("GuidValue").ReadValueFunction(NextRandomGuid),
                        new UADataVariable("Int16Value").ReadValueFunction(NextRandomInt16),
                        new UADataVariable("Int32Value").ReadValueFunction(NextRandomInt32),
                        new UADataVariable("Int64Value").ReadValueFunction(NextRandomInt64),
                        new UADataVariable("SByteValue").ReadValueFunction(NextRandomSByte),
                        new UADataVariable("StringValue").ReadValueFunction(NextRandomString),
                        new UADataVariable("UInt16Value").ReadValueFunction(NextRandomUInt16),
                        new UADataVariable("UInt32Value").ReadValueFunction(NextRandomUInt32),
                        new UADataVariable("UInt64Value").ReadValueFunction(NextRandomUInt64),
                        new UADataVariable("VariantValue").ReadValueFunction(NextRandomVariant)
                    }
                });

            // The FullyWritable sub-folder contains data variables that have not only writable value, but also writable
            // source timestamp and status code.
            dataFolder.Add(
                new UAFolder("FullyWritable")
                {
                    new UAFolder("Scalar")
                    {
                        new UADataVariable("BooleanValue").ReadWriteValue(true)
                            .Writable(true, true, true),
                        new UADataVariable("ByteStringValue").ReadWriteValue(new byte[] { 0x57, 0x21, 0x40, 0xfc })
                            .Writable(true, true, true),
                        new UADataVariable("ByteValue").ReadWriteValue((byte)144)
                            .Writable(true, true, true),
                        new UADataVariable("DateTimeValue").ReadWriteValue(
                                // We are passing in UTC times, because we want always the same result, and so we must specify
                                // the DateTimeKind. You can pass in local times, but then they will be converted to UTC by the
                                // server, and the result will depend on the time zone.
                                DateTime.SpecifyKind(new DateTime(2024, 7, 12, 14, 4, 55).AddSeconds(0.444),
                                    DateTimeKind.Utc))
                            .Writable(true, true, true),
                        new UADataVariable("DoubleValue").ReadWriteValue(7.75630105797e-011)
                            .Writable(true, true, true),
                        new UADataVariable("FloatValue").ReadWriteValue(2.77002e+29f)
                            .Writable(true, true, true),
                        new UADataVariable("GuidValue")
                            .ReadWriteValue(new Guid("{1AEF59AE-5029-42A7-9AE2-B2DC00072999}"))
                            .Writable(true, true, true),
                        new UADataVariable("Int16Value").ReadWriteValue((short)-30956)
                            .Writable(true, true, true),
                        new UADataVariable("Int32Value").ReadWriteValue(276673160)
                            .Writable(true, true, true),
                        new UADataVariable("Int64Value").ReadWriteValue(1412096336825367659)
                            .Writable(true, true, true),
                        new UADataVariable("SByteValue").ReadWriteValue((sbyte)-113)
                            .Writable(true, true, true),
                        new UADataVariable("StringValue").ReadWriteValue("lorem ipsum")
                            .Writable(true, true, true),
                        new UADataVariable("UInt16Value").ReadWriteValue((ushort)64421)
                            .Writable(true, true, true),
                        new UADataVariable("UInt32Value").ReadWriteValue(3853116537U)
                            .Writable(true, true, true),
                        new UADataVariable("UInt64Value").ReadWriteValue(9431348106520835314UL)
                            .Writable(true, true, true),
                        new UADataVariable("VariantValue").ReadWriteValue(529739609)
                            .Writable(true, true, true)
                    }
                });

            // The ReadOnly sub-folder contains data variables that are read-only, and their values can be changed through
            // corresponding data variables in the WriteOnly sub-folder.
            dataFolder.Add(
                new UAFolder("ReadOnly")
                {
                    new UAFolder("Scalar")
                    {
                        booleanReadOnlyDataVariable,
                        byteStringReadOnlyDataVariable,
                        byteReadOnlyDataVariable,
                        dateTimeReadOnlyDataVariable,
                        doubleReadOnlyDataVariable,
                        floatReadOnlyDataVariable,
                        guidReadOnlyDataVariable,
                        int16ReadOnlyDataVariable,
                        int32ReadOnlyDataVariable,
                        int64ReadOnlyDataVariable,
                        sByteReadOnlyDataVariable,
                        stringReadOnlyDataVariable,
                        uInt16ReadOnlyDataVariable,
                        uInt32ReadOnlyDataVariable,
                        uInt64ReadOnlyDataVariable,
                        variantReadOnlyDataVariable
                    }
                });

            // The Static sub-folder contains data variables with static values which can be changed through writing to
            // them (so-called "registers").
            dataFolder.Add(
                new UAFolder("Static")
                {
                    // For demonstration, we consistently create one-dimensional arrays with initially 3 elements, where the
                    // first element has the same value as the scalar variable with the same name.
                    new UAFolder("Array")
                    {
                        new UADataVariable("BooleanValue").ReadWriteValue(new[]
                        {
                            true,
                            false,
                            true
                        }),
                        new UADataVariable("ByteStringValue").ReadWriteValue(new[]
                        {
                            new byte[] { 0x57, 0x21, 0x40, 0xfc },
                            new byte[] { 248, 131, 217, 210 },
                            new byte[] { 252, 152, 119, 65 }
                        }),
                        // This is a tricky case. We want array of Byte-s, but that is automatically recognized as scalar
                        // OPC UA ByteString. For a true array of Byte-s, the data type Id and array dimension list must be
                        // specified explicitly.
                        new UADataVariable("ByteValue").ReadWriteValue(
                            dataTypeId: UADataTypeIds.Byte,
                            arrayRank: 1,
                            value: new byte[]
                            {
                                144,
                                19,
                                233
                            }),
                        new UADataVariable("DateTimeValue").ReadWriteValue(new[]
                        {
                            // We are passing in UTC times, because we want always the same result, and so we must specify
                            // the DateTimeKind. You can pass in local times, but then they will be converted to UTC by the
                            // server, and the result will depend on the time zone.
                            DateTime.SpecifyKind(new DateTime(2024, 7, 12, 14, 4, 55).AddSeconds(0.444),
                                DateTimeKind.Utc),
                            DateTime.SpecifyKind(new DateTime(2024, 4, 8), DateTimeKind.Utc),
                            DateTime.SpecifyKind(new DateTime(2023, 8, 14, 18, 13, 0), DateTimeKind.Utc)
                        }),
                        new UADataVariable("DoubleValue").ReadWriteValue(new[]
                        {
                            7.75630105797e-011,
                            -0.467227097818268,
                            -3.51653052582609E+300
                        }),
                        new UADataVariable("FloatValue").ReadWriteValue(new[]
                        {
                            2.77002e+29f,
                            -1.103936E+36f,
                            -9.002293E-28f
                        }),
                        new UADataVariable("GuidValue").ReadWriteValue(new[]
                        {
                            new Guid("{1AEF59AE-5029-42A7-9AE2-B2DC00072999}"),
                            new Guid("{E8690EA3-25D0-4F19-9DFC-AA25D2772B2F}"),
                            new Guid("{9E081C84-7953-4A88-B709-447FC187EDD9}"),
                        }),
                        new UADataVariable("Int16Value").ReadWriteValue(new short[]
                        {
                            -30956,
                            31277,
                            21977
                        }),
                        new UADataVariable("Int32Value").ReadWriteValue(new[]
                        {
                            276673160,
                            630080334,
                            -391755284
                        }),
                        new UADataVariable("Int64Value").ReadWriteValue(new[]
                        {
                            1412096336825367659,
                            -808781653700434592,
                            4707848393174903135
                        }),
                        new UADataVariable("SByteValue").ReadWriteValue(new sbyte[]
                        {
                            -113,
                            -92,
                            2
                        }),
                        new UADataVariable("StringValue").ReadWriteValue(new[]
                        {
                            "lorem ipsum",
                            "dolor sit amet",
                            "consectetur adipiscing elit"
                        }),
                        new UADataVariable("UInt16Value").ReadWriteValue(new ushort[]
                        {
                            64421,
                            22663,
                            36755
                        }),
                        new UADataVariable("UInt32Value").ReadWriteValue(new uint[]
                        {
                            3853116537,
                            968679231,
                            995611904
                        }),
                        new UADataVariable("UInt64Value").ReadWriteValue(new ulong[]
                        {
                            9431348106520835314,
                            15635738044048254300,
                            946287779964705249
                        }),
                        new UADataVariable("VariantValue").ReadWriteValue(new object[]
                        {
                            529739609,
                            "lorem ipsum",
                            new Guid("{1AEF59AE-5029-42A7-9AE2-B2DC00072999}")
                        })
                    },

                    // We create 2-dimensional arrays with 4x3 size, and default element values.
                    new UAFolder("Array2D")
                    {
                        new UADataVariable("BooleanValue").ReadWriteValue(new bool[4, 3]),
                        new UADataVariable("ByteStringValue").ReadWriteValue(new byte[4, 3][]),
                        new UADataVariable("ByteValue").ReadWriteValue(new byte[4, 3]),
                        new UADataVariable("DateTimeValue").ReadWriteValue(new DateTime[4, 3]),
                        new UADataVariable("DoubleValue").ReadWriteValue(new double[4, 3]),
                        new UADataVariable("FloatValue").ReadWriteValue(new float[4, 3]),
                        new UADataVariable("GuidValue").ReadWriteValue(new Guid[4, 3]),
                        new UADataVariable("Int16Value").ReadWriteValue(new short[4, 3]),
                        new UADataVariable("Int32Value").ReadWriteValue(new int[4, 3]),
                        new UADataVariable("Int64Value").ReadWriteValue(new long[4, 3]),
                        new UADataVariable("SByteValue").ReadWriteValue(new sbyte[4, 3]),
                        new UADataVariable("StringValue").ReadWriteValue(new string[4, 3]),
                        new UADataVariable("UInt16Value").ReadWriteValue(new ushort[4, 3]),
                        new UADataVariable("UInt32Value").ReadWriteValue(new uint[4, 3]),
                        new UADataVariable("UInt64Value").ReadWriteValue(new ulong[4, 3]),
                        new UADataVariable("VariantValue").ReadWriteValue(new object[4, 3])
                    },

                    // Array nodes with specified and enforced maximum array dimensions.
                    new UAFolder("BoundedArray")
                    {
                        new UADataVariable("BooleanValue").ReadWriteValue(new bool[4], arrayDimensions: 5),
                        new UADataVariable("ByteStringValue").ReadWriteValue(new byte[4][], arrayDimensions: 5),
                        // This is a tricky case. We want array of Byte-s, but that is automatically recognized as scalar
                        // OPC UA ByteString. For a true array of Byte-s, the data type Id and array dimension list must be
                        // specified explicitly.
                        new UADataVariable("ByteValue").ReadWriteValue(
                            dataTypeId: UADataTypeIds.Byte,
                            arrayDimensionList: new[] { 5 },
                            new byte[4]),
                        new UADataVariable("DateTimeValue").ReadWriteValue(new DateTime[4], arrayDimensions: 5),
                        new UADataVariable("DoubleValue").ReadWriteValue(new double[4], arrayDimensions: 5),
                        new UADataVariable("FloatValue").ReadWriteValue(new float[4], arrayDimensions: 5),
                        new UADataVariable("GuidValue").ReadWriteValue(new Guid[4], arrayDimensions: 5),
                        new UADataVariable("Int16Value").ReadWriteValue(new short[4], arrayDimensions: 5),
                        new UADataVariable("Int32Value").ReadWriteValue(new int[4], arrayDimensions: 5),
                        new UADataVariable("Int64Value").ReadWriteValue(new long[4], arrayDimensions: 5),
                        new UADataVariable("SByteValue").ReadWriteValue(new sbyte[4], arrayDimensions: 5),
                        new UADataVariable("StringValue").ReadWriteValue(new string[4], arrayDimensions: 5),
                        new UADataVariable("UInt16Value").ReadWriteValue(new ushort[4], arrayDimensions: 5),
                        new UADataVariable("UInt32Value").ReadWriteValue(new uint[4], arrayDimensions: 5),
                        new UADataVariable("UInt64Value").ReadWriteValue(new ulong[4], arrayDimensions: 5),
                        new UADataVariable("VariantValue").ReadWriteValue(new object[4], arrayDimensions: 5)
                    },

                    new UAFolder("Scalar")
                    {
                        new UADataVariable("BooleanValue").ReadWriteValue(true),
                        new UADataVariable("ByteStringValue").ReadWriteValue(new byte[] { 0x57, 0x21, 0x40, 0xfc }),
                        new UADataVariable("ByteValue").ReadWriteValue((byte)144),
                        new UADataVariable("DateTimeValue").ReadWriteValue(
                            // We are passing in UTC times, because we want always the same result, and so we must specify
                            // the DateTimeKind. You can pass in local times, but then they will be converted to UTC by the
                            // server, and the result will depend on the time zone.
                            DateTime.SpecifyKind(new DateTime(2024, 7, 12, 14, 4, 55).AddSeconds(0.444),
                                DateTimeKind.Utc)),
                        new UADataVariable("DoubleValue").ReadWriteValue(7.75630105797e-011),
                        new UADataVariable("FloatValue").ReadWriteValue(2.77002e+29f),
                        new UADataVariable("GuidValue").ReadWriteValue(
                            new Guid("{1AEF59AE-5029-42A7-9AE2-B2DC00072999}")),
                        new UADataVariable("Int16Value").ReadWriteValue((short)-30956),
                        new UADataVariable("Int32Value").ReadWriteValue(276673160),
                        new UADataVariable("Int64Value").ReadWriteValue(1412096336825367659),
                        new UADataVariable("SByteValue").ReadWriteValue((sbyte)-113),
                        new UADataVariable("StringValue").ReadWriteValue("lorem ipsum"),
                        new UADataVariable("UInt16Value").ReadWriteValue((ushort)64421),
                        new UADataVariable("UInt32Value").ReadWriteValue(3853116537U),
                        new UADataVariable("UInt64Value").ReadWriteValue(9431348106520835314UL),
                        new UADataVariable("VariantValue").ReadWriteValue(529739609)
                    }
                });

            // Create and add write-only data variables of various data types. Implement write actions that write the value
            // to the corresponding read-only data variable of the same data type.
            dataFolder.Add(
                new UAFolder("WriteOnly")
                {
                    new UAFolder("Scalar")
                    {
                        new UADataVariable("BooleanValue").Readable(false).WriteValueAction((bool value) =>
                            booleanReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("ByteStringValue").Readable(false).WriteValueAction((byte[] value) =>
                            byteStringReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("ByteValue").Readable(false).WriteValueAction((byte value) =>
                            byteReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("DateTimeValue").Readable(false).WriteValueAction((DateTime value) =>
                            dateTimeReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("DoubleValue").Readable(false).WriteValueAction((double value) =>
                            doubleReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("FloatValue").Readable(false).WriteValueAction((float value) =>
                            floatReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("GuidValue").Readable(false).WriteValueAction((Guid value) =>
                            guidReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("Int16Value").Readable(false).WriteValueAction((short value) =>
                            int16ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("Int32Value").Readable(false).WriteValueAction((int value) =>
                            int32ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("Int64Value").Readable(false).WriteValueAction((long value) =>
                            int64ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("SByteValue").Readable(false).WriteValueAction((sbyte value) =>
                            sByteReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("StringValue").Readable(false).WriteValueAction((string value) =>
                            stringReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("UInt16Value").Readable(false).WriteValueAction((ushort value) =>
                            uInt16ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("UInt32Value").Readable(false).WriteValueAction((uint value) =>
                            uInt32ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("UInt64Value").Readable(false).WriteValueAction((ulong value) =>
                            uInt64ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        new UADataVariable("VariantValue").Readable(false).WriteValueAction((object value) =>
                            variantReadOnlyDataVariable.UpdateReadAttributeData(value))
                    }
                });
        }


        // Random value generators.

        static private readonly Random Random = new Random();

        static private readonly string[] RandomStrings = new[] { "lorem", "ipsum", "dolor", "sit", "amet" };

        static private T[] NextRandomArray<T>(Func<T> nextRandomElement) =>
            new[] { nextRandomElement(), nextRandomElement(), nextRandomElement() };

        static private bool NextRandomBoolean() => Random.Next(2) != 0;

        static private byte NextRandomByte() => (byte)Random.Next(byte.MinValue, byte.MaxValue + 1);

        static private byte[] NextRandomByteString() =>
            new[] { NextRandomByte(), NextRandomByte(), NextRandomByte(), NextRandomByte() };

        static private DateTime NextRandomDateTime() =>
            DateTime.MinValue.AddMilliseconds((DateTime.MaxValue - DateTime.MinValue).TotalMilliseconds *
                                              Random.NextDouble());

        static private float NextRandomFloat() =>
            (float)Math.Pow(10, Math.Log10(float.MaxValue) * Random.NextDouble()) * (2 * Random.Next(2) - 1);

        static private double NextRandomDouble() =>
            Math.Pow(10, Math.Log10(double.MaxValue) * Random.NextDouble()) * (2 * Random.Next(2) - 1);

        static private Guid NextRandomGuid() => Guid.NewGuid();

        static private short NextRandomInt16() => (short)Random.Next(short.MinValue, short.MaxValue + 1);

        static private int NextRandomInt32()
        {
            byte[] buffer = new byte[4];
            Random.NextBytes(buffer);
            return BitConverter.ToInt32(buffer, 0);
        }

        static private long NextRandomInt64()
        {
            byte[] buffer = new byte[8];
            Random.NextBytes(buffer);
            return BitConverter.ToInt64(buffer, 0);
        }

        static private sbyte NextRandomSByte() => (sbyte)Random.Next(sbyte.MinValue, sbyte.MaxValue + 1);

        static private string NextRandomString() => RandomStrings[Random.Next(RandomStrings.Length)];

        static private ushort NextRandomUInt16() => (ushort)Random.Next(ushort.MinValue, ushort.MaxValue + 1);

        static private uint NextRandomUInt32()
        {
            byte[] buffer = new byte[4];
            Random.NextBytes(buffer);
            return BitConverter.ToUInt32(buffer, 0);
        }

        static private ulong NextRandomUInt64()
        {
            byte[] buffer = new byte[8];
            Random.NextBytes(buffer);
            return BitConverter.ToUInt64(buffer, 0);
        }

        static private object NextRandomVariant()
        {
            switch (Random.Next(15))
            {
                case 0:
                    return NextRandomBoolean();
                case 1:
                    return NextRandomByteString();
                case 2:
                    return NextRandomByte();
                case 3:
                    return NextRandomDateTime();
                case 4:
                    return NextRandomDouble();
                case 5:
                    return NextRandomFloat();
                case 6:
                    return NextRandomGuid();
                case 7:
                    return NextRandomInt16();
                case 8:
                    return NextRandomInt32();
                case 9:
                    return NextRandomInt64();
                case 10:
                    return NextRandomSByte();
                case 11:
                    return NextRandomString();
                case 12:
                    return NextRandomUInt16();
                case 13:
                    return NextRandomUInt32();
                case 14:
                    return NextRandomUInt64();
                default:
                    return null;
            }
        }
    }
}
'
' Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
' OPC client and subscriber examples in VB.NET on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-VBNET .
' Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
' a commercial license in order to use Online Forums, and we reply to every post.

Imports System
Imports System.Reactive
Imports Newtonsoft.Json.Linq
Imports OpcLabs.EasyOpc.AlarmsAndEvents.Engine
Imports OpcLabs.EasyOpc.UA.AddressSpace.Standard
Imports OpcLabs.EasyOpc.UA.NodeSpace

'Namespace UAServerDemoLibrary
Public Module DataNodes
        ''' <summary>
        ''' Adds static and dynamic nodes that demonstrate various data types and access levels.
        ''' </summary>
        ''' <param name="parentFolder">The folder to which to add the nodes.</param>
        Sub AddToParent(parentFolder As UAFolder)
            ' Create Data folder.
            Dim dataFolder = UAFolder.CreateIn(parentFolder, "Data")

            ' Create read-only data variables of various data types, without adding them to the server first. We store
            ' references to them individually, because we later implement write-only variables that write to these
            ' read-only variables.
            Dim booleanReadOnlyDataVariable As UADataVariable =
                New UADataVariable("BooleanValue").Writable(False).ValueType(Of Boolean)()
            Dim byteStringReadOnlyDataVariable As UADataVariable =
                New UADataVariable("ByteStringValue").Writable(False).ValueType(Of Byte())()
            Dim byteReadOnlyDataVariable As UADataVariable = New UADataVariable("ByteValue").Writable(False).ValueType(Of Byte)()
            Dim dateTimeReadOnlyDataVariable As UADataVariable =
                New UADataVariable("DateTimeValue").Writable(False).ValueType(Of DateTime)()
            Dim doubleReadOnlyDataVariable As UADataVariable =
                New UADataVariable("DoubleValue").Writable(False).ValueType(Of Double)()
            Dim floatReadOnlyDataVariable As UADataVariable =
                New UADataVariable("FloatValue").Writable(False).ValueType(Of Single)()
            Dim guidReadOnlyDataVariable As UADataVariable = New UADataVariable("GuidValue").Writable(False).ValueType(Of Guid)()
            Dim int16ReadOnlyDataVariable As UADataVariable =
                New UADataVariable("Int16Value").Writable(False).ValueType(Of Short)()
        Dim int32ReadOnlyDataVariable As UADataVariable =
                New UADataVariable("Int32Value").Writable(False).ValueType(Of Integer)()
        Dim int64ReadOnlyDataVariable As UADataVariable =
                New UADataVariable("Int64Value").Writable(False).ValueType(Of Long)()
            Dim sByteReadOnlyDataVariable As UADataVariable =
                New UADataVariable("SByteValue").Writable(False).ValueType(Of SByte)()
            Dim stringReadOnlyDataVariable As UADataVariable =
                New UADataVariable("StringValue").Writable(False).ValueType(Of String)()
            Dim uInt16ReadOnlyDataVariable As UADataVariable =
                New UADataVariable("UInt16Value").Writable(False).ValueType(Of UShort)()
            Dim uInt32ReadOnlyDataVariable As UADataVariable =
                New UADataVariable("UInt32Value").Writable(False).ValueType(Of UInteger)()
            Dim uInt64ReadOnlyDataVariable As UADataVariable =
                New UADataVariable("UInt64Value").Writable(False).ValueType(Of ULong)()
            Dim variantReadOnlyDataVariable As UADataVariable =
                New UADataVariable("VariantValue").Writable(False)

            ' Create Constant sub-folder under the Data folder. It contains read-only data variables with constant values.
            dataFolder.Add(
                New UAFolder("Constant") From
                {
                    New UAFolder("Scalar") From
                    {
                        New UADataVariable("BooleanValue").ConstantValue(True),
                        New UADataVariable("ByteStringValue").ConstantValue(New Byte() {&H57, &H21, &H40, &HFC}),
                        New UADataVariable("ByteValue").ConstantValue(CType(144, Byte)) _
                        , _ ' We are passing In UTC times, because we want always the same result, And so we must specify
                          _ ' the DateTimeKind. You can pass in local times, but then they will be converted to UTC by the
                          _ ' server, And the result will depend on the time zone.
                        New UADataVariable("DateTimeValue").ConstantValue(
                            DateTime.SpecifyKind(New DateTime(2024, 7, 12, 14, 4, 55).AddSeconds(0.444),
                            DateTimeKind.Utc)), _
                                                _
                        New UADataVariable("DoubleValue").ConstantValue(0.0000000000775630105797),
                        New UADataVariable("FloatValue").ConstantValue(2.77002E+29F),
                        New UADataVariable("GuidValue").ConstantValue(
                            New Guid("{1AEF59AE-5029-42A7-9AE2-B2DC00072999}")),
                        New UADataVariable("Int16Value").ConstantValue(CType(-30956, Short)),
                        New UADataVariable("Int32Value").ConstantValue(276673160),
                        New UADataVariable("Int64Value").ConstantValue(1412096336825367659),
                        New UADataVariable("SByteValue").ConstantValue(CType(-113, SByte)),
                        New UADataVariable("StringValue").ConstantValue("lorem ipsum"),
                        New UADataVariable("UInt16Value").ConstantValue(CType(64421, UShort)),
                        New UADataVariable("UInt32Value").ConstantValue(3853116537UI),
                        New UADataVariable("UInt64Value").ConstantValue(9431348106520835314UL),
                        New UADataVariable("VariantValue").ConstantValue(529739609)
                    }
                })

            ' Create Dynamic sub-folder under the Data folder. It contains data variables with dynamically changing values.

            ' This is a tricky case. We want array of Byte-s, but that is automatically recognized as scalar
            ' OPC UA ByteString. For a true array of Byte-s, the data type Id and array dimension list must be
            ' specified explicitly.

            dataFolder.Add(
                New UAFolder("Dynamic") From
                {
                    New UAFolder("Array") From
                    {
                        New UADataVariable("BooleanValue").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomBoolean)),
                        New UADataVariable("ByteStringValue").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomByteString)) _
                        , _ ' This is a tricky case. We want array of Byte-s, but that is automatically recognized as scalar
                          _ ' OPC UA ByteString. For a true array of Byte-s, the data type Id and array dimension list must be
                          _ ' specified explicitly.
                        New UADataVariable("ByteValue").ReadValueFunction(
                            dataTypeId:=UADataTypeIds.Byte,
                            arrayRank:=1,
                            Function() NextRandomArray(AddressOf NextRandomByte)),
                        New UADataVariable("DateTimeValue").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomDateTime)),
                        New UADataVariable("DoubleValue").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomDouble)),
                        New UADataVariable("FloatValue").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomFloat)),
                        New UADataVariable("GuidValue").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomGuid)),
                        New UADataVariable("Int16Value").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomInt16)),
                        New UADataVariable("Int32Value").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomInt32)),
                        New UADataVariable("Int64Value").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomInt64)),
                        New UADataVariable("SByteValue").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomSByte)),
                        New UADataVariable("StringValue").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomString)),
                        New UADataVariable("UInt16Value").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomUInt16)),
                        New UADataVariable("UInt32Value").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomUInt32)),
                        New UADataVariable("UInt64Value").ReadValueFunction(Function() NextRandomArray(AddressOf NextRandomUInt64)),
                        New UADataVariable("VariantValue").ReadValueFunction(Function() NextRandomArray(NextRandomVariant))
                    },
                    New UAFolder("Scalar") From
                    {
                        New UADataVariable("BooleanValue").ReadValueFunction(AddressOf NextRandomBoolean),
                        New UADataVariable("ByteStringValue").ReadValueFunction(AddressOf NextRandomByteString),
                        New UADataVariable("ByteValue").ReadValueFunction(AddressOf NextRandomByte),
                        New UADataVariable("DateTimeValue").ReadValueFunction(AddressOf NextRandomDateTime),
                        New UADataVariable("DoubleValue").ReadValueFunction(AddressOf NextRandomDouble),
                        New UADataVariable("FloatValue").ReadValueFunction(AddressOf NextRandomFloat),
                        New UADataVariable("GuidValue").ReadValueFunction(AddressOf NextRandomGuid),
                        New UADataVariable("Int16Value").ReadValueFunction(AddressOf NextRandomInt16),
                        New UADataVariable("Int32Value").ReadValueFunction(AddressOf NextRandomInt32),
                        New UADataVariable("Int64Value").ReadValueFunction(AddressOf NextRandomInt64),
                        New UADataVariable("SByteValue").ReadValueFunction(AddressOf NextRandomSByte),
                        New UADataVariable("StringValue").ReadValueFunction(AddressOf NextRandomString),
                        New UADataVariable("UInt16Value").ReadValueFunction(AddressOf NextRandomUInt16),
                        New UADataVariable("UInt32Value").ReadValueFunction(AddressOf NextRandomUInt32),
                        New UADataVariable("UInt64Value").ReadValueFunction(AddressOf NextRandomUInt64),
                        New UADataVariable("VariantValue").ReadValueFunction(AddressOf NextRandomVariant)
                    }
                })

            ' The FullyWritable sub-folder contains data variables that have not only writable value, but also writable
            ' source timestamp and status code.
            dataFolder.Add(
                New UAFolder("FullyWritable") From
                {
                    New UAFolder("Scalar") From
                    {
                        New UADataVariable("BooleanValue").ReadWriteValue(True) _
                            .Writable(True, True, True),
                        New UADataVariable("ByteStringValue").ReadWriteValue(New Byte() {&H57, &H21, &H40, &HFC}) _
                            .Writable(True, True, True),
                        New UADataVariable("ByteValue").ReadWriteValue(CType(144, Byte)) _
                            .Writable(True, True, True) _
                             , _ ' We are passing in UTC times, because we want always the same result, and so we must specify
                               _ ' the DateTimeKind. You can pass in local times, but then they will be converted to UTC by the
                               _ ' server, and the result will depend on the time zone.
                        New UADataVariable("DateTimeValue").ReadWriteValue(
                                DateTime.SpecifyKind(New DateTime(2024, 7, 12, 14, 4, 55).AddSeconds(0.444),
                                    DateTimeKind.Utc)) _
                            .Writable(True, True, True),
                        New UADataVariable("DoubleValue").ReadWriteValue(0.0000000000775630105797) _
                            .Writable(True, True, True),
                        New UADataVariable("FloatValue").ReadWriteValue(2.77002E+29F) _
                            .Writable(True, True, True),
                        New UADataVariable("GuidValue") _
                            .ReadWriteValue(New Guid("{1AEF59AE-5029-42A7-9AE2-B2DC00072999}")) _
                            .Writable(True, True, True),
                        New UADataVariable("Int16Value").ReadWriteValue(CType(-30956, Short)) _
                            .Writable(True, True, True),
                        New UADataVariable("Int32Value").ReadWriteValue(276673160) _
                            .Writable(True, True, True),
                        New UADataVariable("Int64Value").ReadWriteValue(1412096336825367659) _
                            .Writable(True, True, True),
                        New UADataVariable("SByteValue").ReadWriteValue(CType(-113, SByte)) _
                            .Writable(True, True, True),
                        New UADataVariable("StringValue").ReadWriteValue("lorem ipsum") _
                            .Writable(True, True, True),
                        New UADataVariable("UInt16Value").ReadWriteValue(CType(64421, UShort)) _
                            .Writable(True, True, True),
                        New UADataVariable("UInt32Value").ReadWriteValue(3853116537UI) _
                            .Writable(True, True, True),
                        New UADataVariable("UInt64Value").ReadWriteValue(9431348106520835314UL) _
                            .Writable(True, True, True),
                        New UADataVariable("VariantValue").ReadWriteValue(529739609) _
                            .Writable(True, True, True)
                    }
                })

            ' The ReadOnly sub-folder contains data variables that are read-only, and their values can be changed through
            ' corresponding data variables in the WriteOnly sub-folder.
            dataFolder.Add(
                New UAFolder("ReadOnly") From
                {
                    New UAFolder("Scalar") From
                    {
                        booleanReadOnlyDataVariable,
                        byteStringReadOnlyDataVariable,
                        byteReadOnlyDataVariable,
                        dateTimeReadOnlyDataVariable,
                        doubleReadOnlyDataVariable,
                        floatReadOnlyDataVariable,
                        guidReadOnlyDataVariable,
                        int16ReadOnlyDataVariable,
                        int32ReadOnlyDataVariable,
                        int64ReadOnlyDataVariable,
                        sByteReadOnlyDataVariable,
                        stringReadOnlyDataVariable,
                        uInt16ReadOnlyDataVariable,
                        uInt32ReadOnlyDataVariable,
                        uInt64ReadOnlyDataVariable,
                        variantReadOnlyDataVariable
                    }
                })

            ' The Static sub-folder contains data variables with static values which can be changed through writing to
            ' them (so-called "registers").

            ' "Array":
            ' For demonstration, we consistently create one-dimensional arrays with initially 3 elements, where the
            ' first element has the same value as the scalar variable with the same name.

            ' "Array.ByteValue":
            ' This is a tricky case. We want array of Byte-s, but that is automatically recognized as scalar
            ' OPC UA ByteString. For a true array of Byte-s, the data type Id and array dimension list must be
            ' specified explicitly.

            ' "Array.DateTimeValue":
            ' We are passing in UTC times, because we want always the same result, and so we must specify
            ' the DateTimeKind. You can pass in local times, but then they will be converted to UTC by the
            ' server, and the result will depend on the time zone.

            ' "Array2D":
            ' We create 2-dimensional arrays with 4x3 size, and default element values.

            ' "BoundedArray":
            ' Array nodes with specified and enforced maximum array dimensions.

            ' "BoundedArray.ByteValue":
            ' This is a tricky case. We want array of Byte-s, but that is automatically recognized as scalar
            ' OPC UA ByteString. For a true array of Byte-s, the data type Id and array dimension list must be
            ' specified explicitly.

            ' "Scalar.DateTimeValue":
            ' We are passing in UTC times, because we want always the same result, and so we must specify
            ' the DateTimeKind. You can pass in local times, but then they will be converted to UTC by the
            ' server, and the result will depend on the time zone.

            dataFolder.Add(
                New UAFolder("Static") From
                { _
                  _ ' For demonstration, we consistently create one-dimensional arrays with initially 3 elements, where the
                  _ ' first element has the same value as the scalar variable with the same name.
                    New UAFolder("Array") From
                    {
                        New UADataVariable("BooleanValue").ReadWriteValue(
                        {
                            True,
                            False,
                            True
                        }),
                        New UADataVariable("ByteStringValue").ReadWriteValue(
                        {
                            New Byte() {&H57, &H21, &H40, &HFC},
                            New Byte() {248, 131, 217, 210},
                            New Byte() {252, 152, 119, 65}
                        }), _
                            _ ' This is a tricky case. We want array of Byte-s, but that is automatically recognized as scalar
                            _ ' OPC UA ByteString. For a true array of Byte-s, the data type Id and array dimension list must be
                            _ ' specified explicitly.
                        New UADataVariable("ByteValue").ReadWriteValue(
                            dataTypeId:=UADataTypeIds.Byte,
                            arrayRank:=1,
                            value:=New Byte() _
                            {
                                144,
                                19,
                                233
                            }),
                        New UADataVariable("DateTimeValue").ReadWriteValue(
                        { _
                          _ ' We are passing in UTC times, because we want always the same result, and so we must specify
                          _ ' the DateTimeKind. You can pass in local times, but then they will be converted to UTC by the
                          _ ' server, and the result will depend on the time zone.
                            DateTime.SpecifyKind(New DateTime(2024, 7, 12, 14, 4, 55).AddSeconds(0.444),
                                DateTimeKind.Utc),
                            DateTime.SpecifyKind(New DateTime(2024, 4, 8), DateTimeKind.Utc),
                            DateTime.SpecifyKind(New DateTime(2023, 8, 14, 18, 13, 0), DateTimeKind.Utc)
                        }),
                        New UADataVariable("DoubleValue").ReadWriteValue(
                        {
                            0.0000000000775630105797,
                            -0.467227097818268,
                            -3.51653052582609E+300
                        }),
                        New UADataVariable("FloatValue").ReadWriteValue(
                        {
                            2.77002E+29F,
                            -1.103936E+36F,
                            -9.002293E-28F
                        }),
                        New UADataVariable("GuidValue").ReadWriteValue(
                        {
                            New Guid("{1AEF59AE-5029-42A7-9AE2-B2DC00072999}"),
                            New Guid("{E8690EA3-25D0-4F19-9DFC-AA25D2772B2F}"),
                            New Guid("{9E081C84-7953-4A88-B709-447FC187EDD9}")
                        }),
                        New UADataVariable("Int16Value").ReadWriteValue(New Short() _
                        {
                            -30956,
                            31277,
                            21977
                        }),
                        New UADataVariable("Int32Value").ReadWriteValue(
                        {
                            276673160,
                            630080334,
                            -391755284
                        }),
                        New UADataVariable("Int64Value").ReadWriteValue(
                        {
                            1412096336825367659,
                            -808781653700434592,
                            4707848393174903135
                        }),
                        New UADataVariable("SByteValue").ReadWriteValue(New SByte() _
                        {
                            -113,
                            -92,
                            2
                        }),
                        New UADataVariable("StringValue").ReadWriteValue(
                        {
                            "lorem ipsum",
                            "dolor sit amet",
                            "consectetur adipiscing elit"
                        }),
                        New UADataVariable("UInt16Value").ReadWriteValue(New UShort() _
                        {
                            64421US,
                            22663US,
                            36755US
                        }),
                        New UADataVariable("UInt32Value").ReadWriteValue(New UInteger() _
                        {
                            3853116537UI,
                            968679231UI,
                            995611904UI
                        }),
                        New UADataVariable("UInt64Value").ReadWriteValue(New ULong() _
                        {
                            9431348106520835314UL,
                            15635738044048254300UL,
                            946287779964705249UL
                        }),
                        New UADataVariable("VariantValue").ReadWriteValue(New Object() _
                        {
                            529739609,
                            "lorem ipsum",
                            New Guid("{1AEF59AE-5029-42A7-9AE2-B2DC00072999}")
                        })
                    }, _
                       _
                       _ ' We create 2-dimensional arrays with 4x3 size, and default element values.
                    New UAFolder("Array2D") From
                    {
                        New UADataVariable("BooleanValue").ReadWriteValue(New Boolean(3, 2) {}),
                        New UADataVariable("ByteStringValue").ReadWriteValue(New Byte(3, 2)() {}),
                        New UADataVariable("ByteValue").ReadWriteValue(New Byte(3, 2) {}),
                        New UADataVariable("DateTimeValue").ReadWriteValue(New DateTime(3, 2) {}),
                        New UADataVariable("DoubleValue").ReadWriteValue(New Double(3, 2) {}),
                        New UADataVariable("FloatValue").ReadWriteValue(New Single(3, 2) {}),
                        New UADataVariable("GuidValue").ReadWriteValue(New Guid(3, 2) {}),
                        New UADataVariable("Int16Value").ReadWriteValue(New Short(3, 2) {}),
                        New UADataVariable("Int32Value").ReadWriteValue(New Integer(3, 2) {}),
                        New UADataVariable("Int64Value").ReadWriteValue(New Long(3, 2) {}),
                        New UADataVariable("SByteValue").ReadWriteValue(New SByte(3, 2) {}),
                        New UADataVariable("StringValue").ReadWriteValue(New String(3, 2) {}),
                        New UADataVariable("UInt16Value").ReadWriteValue(New UShort(3, 2) {}),
                        New UADataVariable("UInt32Value").ReadWriteValue(New UInteger(3, 2) {}),
                        New UADataVariable("UInt64Value").ReadWriteValue(New ULong(3, 2) {}),
                        New UADataVariable("VariantValue").ReadWriteValue(New Object(3, 2) {})
                    }, _
                       _
                       _ ' Array nodes with specified and enforced maximum array dimensions.
                    New UAFolder("BoundedArray") From
                    {
                        New UADataVariable("BooleanValue").ReadWriteValue(New Boolean(3) {}, 5),
                        New UADataVariable("ByteStringValue").ReadWriteValue(New Byte(3)() {}, 5) _
                        , _
                          _ ' This is a tricky case. We want array of Byte-s, but that is automatically recognized as scalar
                          _ ' OPC UA ByteString. For a true array of Byte-s, the data type Id and array dimension list must be
                          _ ' specified explicitly.
                        New UADataVariable("ByteValue").ReadWriteValue(
                            dataTypeId:=UADataTypeIds.Byte,
                            arrayDimensionList:={5},
                            New Byte(3) {}),
                        New UADataVariable("DateTimeValue").ReadWriteValue(New DateTime(3) {}, 5),
                        New UADataVariable("DoubleValue").ReadWriteValue(New Double(3) {}, 5),
                        New UADataVariable("FloatValue").ReadWriteValue(New Single(3) {}, 5),
                        New UADataVariable("GuidValue").ReadWriteValue(New Guid(3) {}, 5),
                        New UADataVariable("Int16Value").ReadWriteValue(New Short(3) {}, 5),
                        New UADataVariable("Int32Value").ReadWriteValue(New Integer(3) {}, 5),
                        New UADataVariable("Int64Value").ReadWriteValue(New Long(3) {}, 5),
                        New UADataVariable("SByteValue").ReadWriteValue(New SByte(3) {}, 5),
                        New UADataVariable("StringValue").ReadWriteValue(New String(3) {}, 5),
                        New UADataVariable("UInt16Value").ReadWriteValue(New UShort(3) {}, 5),
                        New UADataVariable("UInt32Value").ReadWriteValue(New UInteger(3) {}, 5),
                        New UADataVariable("UInt64Value").ReadWriteValue(New ULong(3) {}, 5),
                        New UADataVariable("VariantValue").ReadWriteValue(New Object(3) {}, 5)
                    }, _
                       _
                    New UAFolder("Scalar") From
                    {
                        New UADataVariable("BooleanValue").ReadWriteValue(True),
                        New UADataVariable("ByteStringValue").ReadWriteValue(New Byte() {&H57, &H21, &H40, &HFC}),
                        New UADataVariable("ByteValue").ReadWriteValue(CByte(144)) _
                        , _
                          _ ' We are passing in UTC times, because we want always the same result, and so we must specify
                          _ ' the DateTimeKind. You can pass in local times, but then they will be converted to UTC by the
                          _ ' server, and the result will depend on the time zone.
                        New UADataVariable("DateTimeValue").ReadWriteValue(
                            DateTime.SpecifyKind(New DateTime(2024, 7, 12, 14, 4, 55).AddSeconds(0.444),
                                DateTimeKind.Utc)),
                        New UADataVariable("DoubleValue").ReadWriteValue(0.0000000000775630105797),
                        New UADataVariable("FloatValue").ReadWriteValue(2.77002E+29F),
                        New UADataVariable("GuidValue").ReadWriteValue(
                            New Guid("{1AEF59AE-5029-42A7-9AE2-B2DC00072999}")),
                        New UADataVariable("Int16Value").ReadWriteValue(CType(-30956, Short)),
                        New UADataVariable("Int32Value").ReadWriteValue(276673160),
                        New UADataVariable("Int64Value").ReadWriteValue(1412096336825367659),
                        New UADataVariable("SByteValue").ReadWriteValue(CType(-113, SByte)),
                        New UADataVariable("StringValue").ReadWriteValue("lorem ipsum"),
                        New UADataVariable("UInt16Value").ReadWriteValue(CType(64421, UShort)),
                        New UADataVariable("UInt32Value").ReadWriteValue(3853116537UI),
                        New UADataVariable("UInt64Value").ReadWriteValue(9431348106520835314UL),
                        New UADataVariable("VariantValue").ReadWriteValue(529739609)
                    }
                })

            ' Create and add write-only data variables of various data types. Implement write actions that write the value
            ' to the corresponding read-only data variable of the same data type.
            dataFolder.Add(
                New UAFolder("WriteOnly") From
                {
                    New UAFolder("Scalar") From
                    {
                        New UADataVariable("BooleanValue").Readable(False).WriteValueAction(Sub(value As Boolean) _
                            booleanReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("ByteStringValue").Readable(False).WriteValueAction(Sub(value As Byte()) _
                            byteStringReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("ByteValue").Readable(False).WriteValueAction(Sub(value As Byte) _
                            byteReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("DateTimeValue").Readable(False).WriteValueAction(Sub(value As DateTime) _
                            dateTimeReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("DoubleValue").Readable(False).WriteValueAction(Sub(value As Double) _
                            doubleReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("FloatValue").Readable(False).WriteValueAction(Sub(value As Single) _
                            floatReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("GuidValue").Readable(False).WriteValueAction(Sub(value As Guid) _
                            guidReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("Int16Value").Readable(False).WriteValueAction(Sub(value As Short) _
                            int16ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("Int32Value").Readable(False).WriteValueAction(Sub(value As Integer()) _
                            int32ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("Int64Value").Readable(False).WriteValueAction(Sub(value As Long) _
                            int64ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("SByteValue").Readable(False).WriteValueAction(Sub(value As SByte) _
                            sByteReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("StringValue").Readable(False).WriteValueAction(Sub(value As String) _
                            stringReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("UInt16Value").Readable(False).WriteValueAction(Sub(value As UShort) _
                            uInt16ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("UInt32Value").Readable(False).WriteValueAction(Sub(value As UInteger) _
                            uInt32ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("UInt64Value").Readable(False).WriteValueAction(Sub(value As ULong) _
                            uInt64ReadOnlyDataVariable.UpdateReadAttributeData(value)),
                        New UADataVariable("VariantValue").Readable(False).WriteValueAction(Sub(value As Object) _
                            variantReadOnlyDataVariable.UpdateReadAttributeData(value))
                    }
                })

        End Sub

        ' Random value generators.
        Private ReadOnly Random As Random = New Random()

        Private ReadOnly RandomStrings As String() = {"lorem", "ipsum", "dolor", "sit", "amet"}

        Private Function NextRandomArray(Of T)(nextRandomElement As Func(Of T)) As T()
            Return {nextRandomElement(), nextRandomElement(), nextRandomElement()}
        End Function

        Private Function NextRandomBoolean() As Boolean
            Return Random.Next(2) <> 0
        End Function

        Private Function NextRandomByte() As Byte
            Return CType(Random.Next(Byte.MinValue, Byte.MaxValue + 1), Byte)
        End Function

        Private Function NextRandomByteString() As Byte()
            Return {NextRandomByte(), NextRandomByte(), NextRandomByte(), NextRandomByte()}
        End Function

        Private Function NextRandomDateTime() As DateTime
            Return DateTime.MinValue.AddMilliseconds((DateTime.MaxValue - DateTime.MinValue).TotalMilliseconds *
                                              Random.NextDouble())
        End Function

        Private Function NextRandomFloat() As Single
            Return CType(Math.Pow(10, Math.Log10(Single.MaxValue) * Random.NextDouble()) * (2 * Random.Next(2) - 1), Single)
        End Function

        Private Function NextRandomDouble() As Double
            Return Math.Pow(10, Math.Log10(Double.MaxValue) * Random.NextDouble()) * (2 * Random.Next(2) - 1)
        End Function

        Private Function NextRandomGuid() As Guid
            Return Guid.NewGuid()
        End Function

        Private Function NextRandomInt16() As Short
            Return CType(Random.Next(Short.MinValue, Short.MaxValue + 1), Short)
        End Function

        Private Function NextRandomInt32() As Integer
            Dim buffer As Byte() = New Byte(3) {}
            Random.NextBytes(buffer)
            Return BitConverter.ToInt32(buffer, 0)
        End Function

        Private Function NextRandomInt64() As Long
            Dim buffer As Byte() = New Byte(7) {}
            Random.NextBytes(buffer)
            Return BitConverter.ToInt64(buffer, 0)
        End Function

        Private Function NextRandomSByte() As SByte
            Return CType(Random.Next(SByte.MinValue, SByte.MaxValue + 1), SByte)
        End Function

        Private Function NextRandomString() As String
            Return RandomStrings(Random.Next(RandomStrings.Length))
        End Function

        Private Function NextRandomUInt16() As UShort
            Return CType(Random.Next(UShort.MinValue, UShort.MaxValue + 1), UShort)
        End Function

        Private Function NextRandomUInt32() As UInteger
            Dim buffer As Byte() = New Byte(3) {}
            Random.NextBytes(buffer)
            Return BitConverter.ToUInt32(buffer, 0)
        End Function

        Private Function NextRandomUInt64() As ULong
            Dim buffer As Byte() = New Byte(7) {}
            Random.NextBytes(buffer)
            Return BitConverter.ToUInt64(buffer, 0)
        End Function

        Private Function NextRandomVariant() As Object
            Select Case Random.Next(15)
                Case 0
                    Return NextRandomBoolean()
                Case 1
                    Return NextRandomByteString()
                Case 2
                    Return NextRandomByte()
                Case 3
                    Return NextRandomDateTime()
                Case 4
                    Return NextRandomDouble()
                Case 5
                    Return NextRandomFloat()
                Case 6
                    Return NextRandomGuid()
                Case 7
                    Return NextRandomInt16()
                Case 8
                    Return NextRandomInt32()
                Case 9
                    Return NextRandomInt64()
                Case 10
                    Return NextRandomSByte()
                Case 11
                    Return NextRandomString()
                Case 12
                    Return NextRandomUInt16()
                Case 13
                    Return NextRandomUInt32()
                Case 14
                    Return NextRandomUInt64()
                Case Else
                    Return Nothing
            End Select
        End Function
    End Module
'End Namespace
Requirements

Target Platforms: .NET Framework: Windows 10 (selected versions), Windows 11 (selected versions), Windows Server 2016, Windows Server 2022; .NET: Linux, macOS, Microsoft Windows

See Also